﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using System.Diagnostics;
using zevenseas.LifeCycleManagement.Utilities;
using System.Data;

namespace zevenseas.LifeCycleManagement.TimerJobs
{
    public class SiteLifeCycleActionTimerjob : SPJobDefinition
    {
        public enum Locktype
        {
            NotLocked,
            ReadLocked,
            WriteLocked
        }

        private bool mailOwner;
        private bool lockSite;
        private bool deleteSite;

        private int emailSpan;
        private int lockSpan;
        private int deleteSpan;

        private string emailSubject = string.Empty;
        private string emailBody = string.Empty;
        private string emailTo = string.Empty;

        [Persisted]
        protected int SitesProcessed;

        public int PSitesProcessed { get; set; }

        private ErrorHandling errorHandling;
                       
        public SiteLifeCycleActionTimerjob()
        : base()
        {
          errorHandling = new ErrorHandling();
            errorHandling.productName = "SiteLifeCycleActionTimerJob";
            errorHandling.exeName = "zevenseas.LifeCycleManagement.TimerJobs";
        }

        public SiteLifeCycleActionTimerjob(string name, SPWebApplication webApplication, SPServer server, SPJobLockType lockType)
        : base(name, webApplication, server, lockType)
        {
        }   

        public override void Execute(Guid contentDbId)
        {
            //Getting the configuration of the persistence store
            try
            {                
                SiteLifeCycleSettings settings = this.WebApplication.GetChild<SiteLifeCycleSettings>("SiteLifeCycleSettings");

                deleteSite = settings.deleteSite;
                lockSite = settings.lockSite;
                mailOwner = settings.mailOwner;

                deleteSpan = settings.deleteSpan;
                lockSpan = settings.lockSpan;
                emailSpan = settings.emailSpan;

                emailBody = settings.emailBody;
                emailSubject = settings.emailSubject;

            }
            catch (Exception getConfigurationError) 
            {
                errorHandling.LogMessage(getConfigurationError.Message.ToString(), getConfigurationError);                
            }

            //Looping through all the items in the list
            try
            {
                SPWebApplication webApplication = SPAdministrationWebApplication.Local;
                using (SPWeb web = webApplication.Sites[0].AllWebs["LCM"])
                {
                    SPList unusedSitesList = web.Lists["UnusedSites"];
                    SPQuery qry = new SPQuery();
                    qry.Query = "<Where><Eq><FieldRef Name='WebApplication' /><Value Type='Text'>" + this.WebApplication.Name.ToString() + "</Value></Eq></Where>"; 
                    DataTable dataTable = unusedSitesList.GetItems(qry).GetDataTable();

                    foreach (DataRow item in dataTable.Rows)
                    {
                        DateTime itemAdded = (DateTime)item["Created"];
                        DateTime lastUsageDate = (DateTime)item["LastUsageDate"];
                        string url = item["Url"].ToString();

                        //Before we take any action, we are going to check whether the site is still unused
                        if (CheckIfSiteIsStillUnused(url, lastUsageDate))
                        {
                            switch ((LCMStatus) Enum.Parse(typeof(LCMStatus), item["Status"].ToString()))
                            {
                                case LCMStatus.Mail:
                                    MailAction(unusedSitesList.GetItemById(int.Parse(item["ID"].ToString())));
                                    break;
                                case LCMStatus.Lock:
                                    LockAction(unusedSitesList.GetItemById(int.Parse(item["ID"].ToString())));
                                    break;
                                case LCMStatus.Delete:
                                    DeleteAction(unusedSitesList.GetItemById(int.Parse(item["ID"].ToString())));                                        
                                    break;
                            }                                
                        }

                        this.SitesProcessed++;
                        this.Update();
                    }
                }
            }

            catch (Exception loopError)
            {
                errorHandling.LogMessage(loopError.Message.ToString(), loopError);
            }

            //Storing the lastRunTime to show on the Overview Sites page
            if (this.Title == "LCMActionJob_Manual")
            {
                ActionTimerJobStatus status = WebApplication.GetChild<ActionTimerJobStatus>("ActionTimerJobStatus");
                if (status == null)
                {
                    SPPersistedObject parent = WebApplication;
                    status = new ActionTimerJobStatus("ActionTimerJobStatus", parent, Guid.NewGuid());
                    status.Update();
                }
                status.LastRunTime = this.LastRunTime;
                status.Update();

            }
        }

        public void DeleteAction(SPListItem item)
        {
            if (item["Deleted"] == null)
            {
                if (DeleteSite(item["Url"].ToString()))
                {
                    item["Deleted"] = true;
                    item["DeletedAt"] = System.DateTime.Today;
                    item.Update();
                }
            }
        }

        public void MailAction(SPListItem item)
        {
            if (item["Mailed"] != null)
            {
                DateTime mailedAt = (DateTime)item["MailedAt"];
                //If the date exceeds the timespan of mailing then go to the next action
                if (mailedAt.AddDays(emailSpan).Date >= System.DateTime.Today.Date)
                {
                    //Change the status from mailing to the next action status
                    if (deleteSite)
                    {
                        item["Status"] = LCMStatus.Delete.ToString();
                    }
                    if (lockSite)
                    {
                        item["Status"] = LCMStatus.Lock.ToString();
                    }
                    item.Update();                    
                }
            }
            else
            {
                try
                {
                    //sending email
                    emailTo = item["OwnerEmailAddress"].ToString();
                    emailSubject = item["Title"] + " at : " + item["Url"] + emailSubject;
                    if (SPUtility.SendEmail(item.ParentList.ParentWeb, false, true, emailTo, emailSubject, emailBody))
                    {
                        //updating list if email is successfully sent
                        item["MailedAt"] = System.DateTime.Today;
                        item["Mailed"] = true;
                        item.Update();
                    }
                }
                catch (Exception mailError)
                {
                    errorHandling.LogMessage(mailError.Message.ToString(), mailError);
                }
            }


        }

        public void LockAction(SPListItem item)
        {
            //Checking if the site is already locked
            if (item["Locked"] == null)
            {
                if (LockSite(item["Url"].ToString(), Locktype.WriteLocked))
                {
                    item["Locked"] = "Write Locked";
                    item["LockedAt"] = System.DateTime.Today;
                    item.Update();
                }
            }
            else
            { 
                DateTime lockedAt = (DateTime)item["LockedAt"];
                //If the date exceeds the timespan of locking then go to the next action
                if (lockedAt.AddDays(lockSpan).Date >= System.DateTime.Today.Date)
                {
                    //Change the status from mailing to the next action status
                    if (deleteSite)
                    {
                        item["Status"] = LCMStatus.Delete.ToString();
                    }                   
                    item.Update();
                }
            }            
        }

        public bool DeleteSite(string siteUrl)
        {
            bool siteDeleted = false;
            SPSite site = null;
            SPWeb web = null;

            try
            {
                site = new SPSite(siteUrl);
                web = site.OpenWeb();

                if (web.IsRootWeb)
                {
                    site.Delete();
                }
                else
                {
                    web.Delete();
                }
                siteDeleted = true;
            }
            catch (Exception deleteSiteError)
            {
                siteDeleted = false;
                errorHandling.LogMessage(deleteSiteError.Message.ToString(), deleteSiteError);
            }

            return siteDeleted;
        }

        private bool LockSite(string siteUrl, Locktype lockType)
        {
            bool siteLocked = false;
            SPSiteAdministration site = null;

            try
            {
                site = new SPSiteAdministration(siteUrl);
                site.WriteLocked = true;
                //switch (lockType)
                //{
                //    case Locktype.NotLocked:
                //        site.ReadLocked = false;
                //        site.WriteLocked = false;
                //        break;                        
                //    case Locktype.WriteLocked:
                //        site.WriteLocked = true;
                //        site.ReadLocked = false;
                //       // site.LockIssue = "This site has been locked because it is marked as unused. Please contact your SharePoint IT Team to unlock this site if you wish to do so";
                //        break;
                //}

                siteLocked = true;
                

            }
            catch (Exception siteLockError)
            {
                siteLocked = false;
                errorHandling.LogMessage(siteLockError.Message.ToString(), siteLockError);
            }
            finally
            {                
                site.Dispose();
            }

            return siteLocked;
        }

        private bool CheckIfSiteIsStillUnused(string url, DateTime lastUsageDate)
        {
            bool siteIsUnused = false;
            SPSite site = null;
             
            try
            {
                try
                {
                    site = new SPSite(url);
                }
                catch (Exception)
                { 
                    //Site is already deleted by the user
                }

                if (site != null)
                {                    
                    List<DateTime> dates = new List<DateTime>();
                    dates.Add(site.LastContentModifiedDate);
                    dates.Add(site.LastSecurityModifiedDate);
                    dates.Add(Utilities.Utilities.GetLastUsageDate(site.RootWeb));

                    //Sorting the list puts the newest date at the bottom of the array
                    dates.Sort();
                    DateTime latestDate = dates[dates.Count - 1];

                    //Check if the previously added date is the same date.
                    if (latestDate == lastUsageDate)
                    {
                        siteIsUnused = true;
                    }                    
                }
            }
            catch (Exception)
            { }
            finally
            {
                site.Close();
                site.Dispose();
            }

            return siteIsUnused;
        }
    }
}
